/*******************************************************************************

  Pilot Intelligence Library
    https://gitee.com/pi-lab

*******************************************************************************/

/*
 * https://www.cnblogs.com/HpeMephisto/p/11312193.html
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <map>
#include <thread>


#ifdef _WIN32
#include <winsock2.h>
#pragma comment (lib, "WS2_32.lib")
#include <io.h> //代替unistd.h的一些基本操作
#include <ws2tcpip.h> //代替unistd.h中的socklen_t
#define  MSG_NOSIGNAL 0
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <fcntl.h>
#endif


#include "utils_debug.h"
#include "Socket++.h"
#include "utils.h"
#include "../core/Timer.h"
#include "../core/RingBuffer.h"


namespace pi {


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

class RSocket_PrivateData
{
public:
    RSocket_PrivateData() {
        memset(&m_addr, 0, sizeof(sockaddr_in));
        memset(&m_addrClient, 0, sizeof(sockaddr_in));

        m_tcpServerAlive = 0;
        m_thread_acceptClient = nullptr;

        m_socketSelf = nullptr;
    }

    ~RSocket_PrivateData() {
        memset(&m_addr, 0, sizeof(sockaddr_in));
        memset(&m_addrClient, 0, sizeof(sockaddr_in));
    }

    void startTCPServer(void) {
        if( m_thread_acceptClient ) {
            stopTCPServer();
        }

        m_clientsReadBuf = new pi::RingBuffer<char>(32*1024*1024);
        m_thread_acceptClient = new std::thread(&RSocket_PrivateData::threadFunc_ClientAccept, this);
    }

    void stopTCPServer(void) {
        // set thread stop flag
        m_tcpServerAlive = 0;

        // close all client read thread
        for(auto t : m_arrClientThread) {
            t->join();
            delete t;
        }

        // close all client socket
        for(auto s : m_arrClientSocket ) {
            s->close();
            delete s;
        }

        // stop server accept thread
        if( m_thread_acceptClient ) {
            m_thread_acceptClient->join();
            delete m_thread_acceptClient;
            m_thread_acceptClient = nullptr;
        }

        m_arrClientThread.clear();
        m_arrClientSocket.clear();

        delete m_clientsReadBuf;
        m_clientsReadBuf = nullptr;
    }

    void threadFunc_ClientAccept(void) {
        m_tcpServerAlive = 1;

        GSLAM::Rate r(2000);

        RSocket *socketClient = new RSocket();

        while( m_tcpServerAlive ) {
            // accept new client
            if (0 != m_socketSelf->accept(*socketClient))
            {
                tm_sleep(10);
                continue;
            }

            RSocketAddress ca;
            socketClient->getClientAddress(ca);

            dbg_pi("accept a new connection! client: %s:%d\n",
                   ca.addr_str, ca.port);

            m_arrClientSocket.push_back(socketClient);

            std::thread *threadRead = new std::thread([socketClient, this]() {
                const int buf_r_len = 1024*16;
                char buf_r[buf_r_len];
                int ret;

                while( this->m_tcpServerAlive ) {
                    ret = socketClient->recv(buf_r, buf_r_len);
                    if( ret <= 0 ) {
                        tm_sleep(1);
                        continue;
                    }

                    m_clientsReadBuf->write(buf_r, ret);
                }
            });
            m_arrClientThread.push_back(threadRead);

            socketClient = new RSocket();
        }

        delete socketClient;
    }

    /**
     * @brief TCP server send message to all clients
     *
     * @param dat       - [in] data buffer
     * @param len       - [in] data length
     *
     * @return
     *      -1          - Client not connected
     *      0           - Do not read data
     *      >0 value    - send data length
     */
    int send(const char *dat, int len) {
        if( !m_tcpServerAlive ) return -1;
        int ret = 0;

        for(auto s : m_arrClientSocket) {
            ret = s->send(dat, len);
        }

        return ret;
    }

    /**
     * @brief TCP server recv data from all clients
     *        NOTE: all client data are mixed into a RingBuffer, can not identify data's sender
     *
     * @param dat       - Received data buffer
     * @param len       - Desired recv data length
     *
     * @return
     *      -1          - Client not connected
     *      0           - No data aviable
     *      >0          - Received data length
     */
    int recv(char *dat, int len) {
        int ret=0;

        if( !m_tcpServerAlive ) return -1;

        ret = m_clientsReadBuf->read(dat, len);

        return ret;
    }


public:
    pi::RSocket*    m_socketSelf;
    sockaddr_in     m_addr;
    sockaddr_in     m_addrClient;
    sockaddr_in     remote_addr;

    std::map<uint64_t, sockaddr_in> m_mapClients;

    // TCP server
    int                         m_tcpServerAlive;
    std::thread                 *m_thread_acceptClient;
    std::vector<pi::RSocket*>   m_arrClientSocket;
    std::vector<std::thread*>   m_arrClientThread;
    pi::RingBuffer<char>        *m_clientsReadBuf;
};



////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

int RSocket::m_bInitialized = 0;


RSocket::RSocket() : m_sock ( -1 )
{
    if( !m_bInitialized ) {
        #ifdef _WIN32
           WORD versionWanted = MAKEWORD(1, 1);
           WSADATA wsaData;
           WSAStartup(versionWanted, &wsaData);

           m_bInitialized = 1;
        #endif
    }

    RSocket_PrivateData *pd = new RSocket_PrivateData;
    m_priData = pd;
    pd->m_socketSelf = this;

    m_socketType = SOCKET_TCP;
    m_server = 0;

    m_maxConnections = 500;
    m_maxHostname    = 1024;
}

RSocket::~RSocket()
{
    if (isOpened())
#ifdef _WIN32
        closesocket(m_sock);
#else
        ::close(m_sock);
#endif

    RSocket_PrivateData *pd = (RSocket_PrivateData*) m_priData;
    delete pd;
    m_priData = nullptr;
}

int RSocket::create(void)
{
    // create socket
    if( m_socketType == SOCKET_TCP )
        m_sock = socket(AF_INET, SOCK_STREAM, 0);
    else
        m_sock = socket(AF_INET, SOCK_DGRAM, 0);

    // check socket created or not
    if ( !isOpened() )
        return -1;

    // set SO_REUSEADDR on
    if( m_socketType == SOCKET_TCP ||
        //(m_socketType == SOCKET_UDP_MULTICAST && !m_server) )  {
        m_socketType == SOCKET_UDP_MULTICAST ) {
        m_sock = socket(AF_INET, SOCK_DGRAM, 0);
        setReuseAddr(1);

    }

    return 0;
}

int RSocket::close(void)
{
    RSocket_PrivateData *pd = (RSocket_PrivateData*) m_priData;

    if( m_server && m_socketType == SOCKET_TCP ) {
        pd->stopTCPServer();
    }

    if ( isOpened() )
#ifdef _WIN32
        closesocket(m_sock);
#else
        ::close(m_sock);
#endif

    m_sock = -1;
    m_server = 0;

    return 0;
}

int RSocket::bind(int port)
{
    RSocket_PrivateData *pd = (RSocket_PrivateData*) m_priData;

    if ( !isOpened() ) {
        return -1;
    }

    pd->m_addr.sin_family       = AF_INET;
    pd->m_addr.sin_addr.s_addr  = htonl(INADDR_ANY);
    pd->m_addr.sin_port         = htons(port);

    int ret = ::bind(m_sock, (struct sockaddr*) &(pd->m_addr), sizeof(pd->m_addr));
    if ( ret == -1 ) {
        return -2;
    }

    return 0;
}


int RSocket::listen(void)
{
    if ( !isOpened() ) {
        return -1;
    }

    int listen_return = ::listen(m_sock, m_maxConnections);

    if ( listen_return == -1 ) {
        return -2;
    }

    return 0;
}


int RSocket::accept(RSocket& new_socket)
{
    RSocket_PrivateData *pd = (RSocket_PrivateData*) new_socket.m_priData;

    int addr_length = sizeof(pd->m_addrClient);
    new_socket.m_sock = ::accept(m_sock,
                                 (sockaddr*) &(pd->m_addrClient),
                                 (socklen_t*) &addr_length);

    if ( new_socket.m_sock <= 0 )
        return -1;
    else
        return 0;
}

int RSocket::send(const char *dat, int len)
{
    RSocket_PrivateData *pd = (RSocket_PrivateData*) m_priData;

    if( m_socketType == SOCKET_TCP ) {
        if( m_server ) {
            // TCP server
            return pd->send(dat, len);
        } else {
            // TCP client
            return ::send(m_sock, dat, len, MSG_NOSIGNAL); // 如果在Windows系统下面MSG_NOSIGNAL该函数就有定义为0，如果是linux就为默认
        }
    } else if( m_socketType == SOCKET_UDP ) {
        if( m_server ) {
            // UDP server
            int ret = 0;

            // for each client
            //dbg_pe("client num = %ld\n", pd->m_mapClients.size());
            for(auto i = pd->m_mapClients.begin(); i != pd->m_mapClients.end(); ++i) {
                sockaddr_in sai = i->second;

                ret = ::sendto(m_sock, dat, len, 0,
                               (struct sockaddr *) &(sai), sizeof(sai));

                if( ret <= 0 ) {
                    // remove losted client
                    //pd->m_mapClients.erase(i);
                }
            }

            return ret;
        } else {
            // UDP client
            return ::sendto(m_sock, dat, len, 0,
                          (struct sockaddr *) &(pd->m_addr), sizeof(pd->m_addr));
        }
    } else if( m_socketType == SOCKET_UDP_MULTICAST ) {
        return ::sendto(m_sock, dat, len, 0,
                        (struct sockaddr *) &(pd->remote_addr), sizeof(pd->remote_addr));
    }

    return -1;
}


int RSocket::send (const std::string &s)
{
    return send((const char*)s.c_str(), s.size());
}

int RSocket::recv(char *dat, int len)
{
    RSocket_PrivateData *pd = (RSocket_PrivateData*) m_priData;

    if( m_socketType == SOCKET_TCP )        
        if( m_server ) {
            // TCP server
            return pd->recv(dat, len);
        } else {
            // TCP client
            return ::recv(m_sock, dat, len, 0);
        }
    else if( m_socketType == SOCKET_UDP ) {
        socklen_t addrLen = sizeof(pd->m_addrClient);
        sockaddr_in addr;

        if( m_server ) {
            int ret = ::recvfrom(m_sock, dat, len, 0,
                              (struct sockaddr *) &addr, &addrLen);

            int port = ntohs(addr.sin_port);
            if( ret <= 0 || port == 0 ) return ret;

            char addr_str[32];
            inet_ntop(AF_INET, &(addr.sin_addr), addr_str, INET_ADDRSTRLEN);
            //dbg_pt("recvfrom %s:%d len=%d\n", addr_str, port, ret);

            memcpy(&(pd->m_addrClient), &addr, sizeof(addr)); // set new connected client addr

            uint64_t port_64 = addr.sin_port;
            uint64_t addr_key = addr.sin_addr.s_addr | port_64 << 32;
            if( pd->m_mapClients.find(addr_key) == pd->m_mapClients.end() ) {
                pd->m_mapClients.insert(std::make_pair(addr_key, addr));

                int my_port = ntohs(pd->m_addr.sin_port);
                char my_addr_str[32];
                inet_ntop(AF_INET, &(pd->m_addr.sin_addr), my_addr_str, INET_ADDRSTRLEN);

                dbg_pi("new client: %s:%d [my addr:port %s:%d]\n",
                       addr_str, port,
                       my_addr_str, my_port);
            }
            return ret;
        } else {
            int ret = ::recvfrom(m_sock, dat, len, 0,
                              (struct sockaddr *) &addr, &addrLen);

            int port = ntohs(addr.sin_port);
            if( ret <= 0 || port == 0 ) return ret;

            char addr_str[32];
            inet_ntop(AF_INET, &(addr.sin_addr), addr_str, INET_ADDRSTRLEN);
            int my_port = ntohs(pd->m_addr.sin_port);
            char my_addr_str[32];
            inet_ntop(AF_INET, &(pd->m_addr.sin_addr), my_addr_str, INET_ADDRSTRLEN);

            (void) my_port;

            //dbg_pt("RSocket::recv >> UDP client recv from %s:%d [my addr:port %s:%d]\n",
            //       addr_str, port,
            //       my_addr_str, my_port);

            return ret;
        }
    } else if( m_socketType == SOCKET_UDP_MULTICAST ) {
        socklen_t addrLen = sizeof(pd->m_addr);
        return ::recvfrom(m_sock, dat, len, 0,
                          (struct sockaddr *) &(pd->m_addr), &addrLen);
    }

    return -1;
}


// int RSocket::recv(uint8_t *dat, int len)
// {
//     RSocket_PrivateData *pd = (RSocket_PrivateData*) m_priData;

//     if( m_socketType == SOCKET_TCP )
//         if( m_server ) {
//             // TCP server
//             return pd->recv(dat, len);
//         } else {
//             // TCP client
//             return ::recv(m_sock, dat, len, 0);
//         }
//     else if( m_socketType == SOCKET_UDP ) {
//         socklen_t addrLen = sizeof(pd->m_addrClient);
//         sockaddr_in addr;

//         if( m_server ) {
//             int ret = ::recvfrom(m_sock, dat, len, 0,
//                                  (struct sockaddr *) &addr, &addrLen);

//             int port = ntohs(addr.sin_port);
//             if( ret <= 0 || port == 0 ) return ret;

//             char addr_str[32];
//             inet_ntop(AF_INET, &(addr.sin_addr), addr_str, INET_ADDRSTRLEN);
//             //dbg_pt("recvfrom %s:%d len=%d\n", addr_str, port, ret);

//             memcpy(&(pd->m_addrClient), &addr, sizeof(addr)); // set new connected client addr

//             uint64_t port_64 = addr.sin_port;
//             uint64_t addr_key = addr.sin_addr.s_addr | port_64 << 32;
//             if( pd->m_mapClients.find(addr_key) == pd->m_mapClients.end() ) {
//                 pd->m_mapClients.insert(std::make_pair(addr_key, addr));

//                 int my_port = ntohs(pd->m_addr.sin_port);
//                 char my_addr_str[32];
//                 inet_ntop(AF_INET, &(pd->m_addr.sin_addr), my_addr_str, INET_ADDRSTRLEN);

//                 dbg_pi("new client: %s:%d [my addr:port %s:%d]\n",
//                        addr_str, port,
//                        my_addr_str, my_port);
//             }
//             return ret;
//         } else {
//             int ret = ::recvfrom(m_sock, dat, len, 0,
//                                  (struct sockaddr *) &addr, &addrLen);

//             int port = ntohs(addr.sin_port);
//             if( ret <= 0 || port == 0 ) return ret;

//             char addr_str[32];
//             inet_ntop(AF_INET, &(addr.sin_addr), addr_str, INET_ADDRSTRLEN);
//             int my_port = ntohs(pd->m_addr.sin_port);
//             char my_addr_str[32];
//             inet_ntop(AF_INET, &(pd->m_addr.sin_addr), my_addr_str, INET_ADDRSTRLEN);

//             (void) my_port;

//             //dbg_pt("RSocket::recv >> UDP client recv from %s:%d [my addr:port %s:%d]\n",
//             //       addr_str, port,
//             //       my_addr_str, my_port);

//             return ret;
//         }
//     } else if( m_socketType == SOCKET_UDP_MULTICAST ) {
//         socklen_t addrLen = sizeof(pd->m_addr);
//         return ::recvfrom(m_sock, dat, len, 0,
//                           (struct sockaddr *) &(pd->m_addr), &addrLen);
//     }

//     return -1;
// }

int RSocket::recv(std::string& s, int maxLen)
{
    char *buf;
    int status = 0;

    buf = new char[maxLen + 1];
    memset(buf, 0, maxLen + 1);
    s = "";

    status = recv((char*) buf, maxLen);
    if ( status > 0 ) s = buf;

    delete [] buf;
    
    return status;
}


int RSocket::recv_until(uint8_t *dat, int len)
{
    uint8_t     *p;
    int         ret, read, readed = 0;

    p    = dat;
    read = len;

    while(1) {
        ret = recv((char* )p, read);
        if( ret < 0 ) return ret;

        readed += ret;
        p      += ret;

        if( readed >= len ) return readed;

        read = len - readed;
    }

    return -1;
}


int RSocket::connect(std::string host, int port)
{
    uint32_t addr;

    inet_pton(AF_INET, host.c_str(), &addr);
    if ( errno == EAFNOSUPPORT )
        return -1;

    return connect(addr, port);
}


int RSocket::connect(uint32_t addr, int port)
{
    RSocket_PrivateData *pd = (RSocket_PrivateData*) m_priData;

    if ( ! isOpened() ) return -1;

    pd->m_addr.sin_family       = AF_INET;
    pd->m_addr.sin_port         = htons(port);
    pd->m_addr.sin_addr.s_addr  = addr;

    if( m_socketType == SOCKET_TCP ) {
        int status = ::connect(m_sock, (sockaddr *) &(pd->m_addr), sizeof(pd->m_addr) );

        if ( status == 0 )
            return 0;
        else
            return -3;
    } else {
        return 0;
    }
}

int RSocket::startServer(int port, RSocketType t)
{
    RSocket_PrivateData *pd = (RSocket_PrivateData*) m_priData;

    m_socketType = t;
    m_server = 1;

    if ( 0 != create() ) {
        return -1;
    }

    if ( 0 != bind (port) ) {
        return -2;
    }

    if( m_socketType == SOCKET_TCP ) {
        if ( 0 != listen() ) return -3;

        pd->startTCPServer();
    }

    return 0;
}

int RSocket::startServer(const std::string& addr, int port, RSocketType t)
{
    RSocket_PrivateData *pd = (RSocket_PrivateData*) m_priData;

    m_socketType = t;
    m_server = 1;

    if ( 0 != create() ) {
        return -1;
    }

    if( t != SOCKET_UDP_MULTICAST ) {
        if ( 0 != bind (port) ) {
            return -2;
        }
    } else {
        memset(&(pd->m_addr), 0, sizeof(pd->m_addr));
        pd->m_addr.sin_family       = AF_INET;

#ifdef _WIN32
        pd->m_addr.sin_addr.s_addr = inet_pton(AF_INET,addr.c_str(), &pd->m_addr.sin_addr.s_addr);
#else
        pd->m_addr.sin_addr.s_addr = inet_addr(addr.c_str());
#endif
        pd->m_addr.sin_port         = htons(port);
    }

    if( m_socketType == SOCKET_TCP ) {
        if ( 0 != listen() ) return -3;

        pd->startTCPServer();
    }

    return 0;
}

int RSocket::setRemoteAddr(const std::string& host, int port){
    RSocket_PrivateData *pd = (RSocket_PrivateData*) m_priData;
    memset(&pd->remote_addr,0,sizeof(pd->remote_addr));

    pd->remote_addr.sin_family=AF_INET;
    pd->remote_addr.sin_addr.s_addr=inet_addr(host.c_str());
    pd->remote_addr.sin_port=htons(port);
    return 0;

}

int RSocket::startClient(const std::string& host, int port, RSocketType t)
{
    uint32_t addr;
    m_server = 0;

    inet_pton(AF_INET, host.c_str(), &addr);
    if ( errno == EAFNOSUPPORT )
        return -1;

#ifdef _WIN32
    // inet_pton这个函数与inet_addr最大的区别在于return的值不一样，不能简单的照抄形式
    inet_pton(AF_INET, host.c_str(), &addr);
#else
    addr = inet_addr(host.c_str());
#endif

    return startClient(addr, port, t);
}



int RSocket::startClient(uint32_t addr, int port, RSocketType t)
{
    m_socketType = t;
    m_server = 0;

    if ( 0 != create() ) {
        return -1;
    }

    if( t == SOCKET_UDP_MULTICAST ) {
        RSocket_PrivateData *pd = (RSocket_PrivateData*) m_priData;

        memset(&(pd->m_addr), 0, sizeof(pd->m_addr));

        pd->m_addr.sin_family       = AF_INET;
        pd->m_addr.sin_addr.s_addr  = htonl(INADDR_ANY);
        pd->m_addr.sin_port         = htons(port);
        // bind to receive address
        if ( ::bind(m_sock, (struct sockaddr *) &(pd->m_addr), sizeof(pd->m_addr)) < 0 ) {
            dbg_pe("Failed to bind UDP port [%d]", port);
            return -2;
        }

        // use setsockopt() to request that the kernel join a multicast group
        struct ip_mreq mreq;
        mreq.imr_multiaddr.s_addr = addr;
        mreq.imr_interface.s_addr = htonl(INADDR_ANY);

        // 函数存在偏差
        #ifdef _WIN32
            if (setsockopt(m_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                       (char *)&mreq, sizeof(mreq)) < 0) {
            dbg_pe("Failed to setsockopt for setting join a multicast group");
            return -3;
        }
        #else
         if (setsockopt(m_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                       &mreq, sizeof(mreq)) < 0) {
            dbg_pe("Failed to setsockopt for setting join a multicast group");
            return -3;
        }
        #endif

    } else {
        if ( 0 != connect(addr, port) ) {
            return -2;
        }
    }

    return 0;
}


int RSocket::getMyAddress(RSocketAddress &a)
{
    RSocket_PrivateData *pd = (RSocket_PrivateData*) m_priData;

    a.port      = ntohs(pd->m_addr.sin_port);
    a.addr_inet = ntohl(pd->m_addr.sin_addr.s_addr);
    inet_ntop(AF_INET, &(pd->m_addr.sin_addr),
              a.addr_str, INET_ADDRSTRLEN);
    a.type = m_socketType;

    return 0;
}

int RSocket::getClientAddress(RSocketAddress &a)
{
    RSocket_PrivateData *pd = (RSocket_PrivateData*) m_priData;

    a.port      = ntohs(pd->m_addrClient.sin_port);
    a.addr_inet = ntohl(pd->m_addrClient.sin_addr.s_addr);
    inet_ntop(AF_INET, &(pd->m_addrClient.sin_addr),
              a.addr_str, INET_ADDRSTRLEN);
    a.type = m_socketType;

    return 0;
}

int RSocket::getClientAddressArray(std::vector<RSocketAddress> &addr)
{
    RSocket_PrivateData *pd = (RSocket_PrivateData*) m_priData;

    addr.clear();
    for(auto const& i : pd->m_mapClients) {
        RSocketAddress sa;
        sa.addr_inet = ntohl(i.second.sin_addr.s_addr);
        sa.port = ntohs(i.second.sin_port);
        inet_ntop(AF_INET, &(i.second.sin_addr), sa.addr_str, INET_ADDRSTRLEN);
        sa.type = m_socketType;

        addr.push_back(sa);
    }

    return addr.size();
}


#ifdef _WIN32
int RSocket::setNonBlocking(int nb)
{
    int opts,flag;
    flag = 1;
    opts = ioctlsocket(m_sock,FIONBIO,(unsigned long*)&flag);

    if ( opts < 0 ) {
        return -1;
    }

    if ( nb )
        opts = 1;
    else
        opts = 0;
    ioctlsocket(m_sock, FIONBIO,(unsigned long*)&opts);

    return 0;
}
#else
int RSocket::setNonBlocking(int nb)
{
    int opts;

    opts = fcntl(m_sock, F_GETFL);

    if ( opts < 0 ) {
        return -1;
    }

    if ( nb )
        opts = opts | O_NONBLOCK;
    else
        opts = opts & ~O_NONBLOCK;

    fcntl(m_sock, F_SETFL, opts);

    return 0;
}
#endif



int RSocket::setReuseAddr(uint32_t reuse)
{
    int ret = setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR,
                         (const char*) &reuse, sizeof(reuse));
    if( ret == -1 ) {
        dbg_pe("setsockopt failed");
    }

    return ret;
}


int RSocket::getRecvBuffSize(void)
{
    size_t bufsize;
    socklen_t optlen = sizeof(int);

#ifdef _WIN32
    return 4096;
#else
    auto res = getsockopt(m_sock, SOL_SOCKET, SO_RCVBUF, &bufsize, &optlen);
    if( res == -1 ) return -1;
    return bufsize;
#endif
}

int RSocket::setRecvBuffSize(int bufsize)
{
#ifdef _WIN32
    return 0;
#else
    size_t sendBuff = bufsize;
    socklen_t optlen = sizeof(int);

    (void) optlen;

    if ( setsockopt(m_sock, SOL_SOCKET, SO_RCVBUF, &sendBuff, sizeof(sendBuff) ) == -1 )
    {
        return -1;
    }

    return 0;
#endif
}

} // end of namespace pi
